package com.android.camera.one.v2.camera2proxy;

import java.util.concurrent.atomic.AtomicBoolean;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;

import com.android.camera.one.v2.camera2proxy.ImageWriterProxy.OnImageReleasedListener;
import com.google.common.base.Objects;

import android.graphics.ImageFormat;
import android.media.Image;
import android.media.ImageWriter;
import android.os.Handler;
import android.view.Surface;

public class AndroidImageWriterProxy implements ImageWriterProxy{
	private final Object mLock;
    @GuardedBy("mLock")
    private final android.media.ImageWriter mDelegate;
    private final AtomicBoolean mClosed;

    private AndroidImageWriterProxy(android.media.ImageWriter delegate) {
        mLock = new Object();
        mDelegate = delegate;
        mClosed = new AtomicBoolean();
    }
    
    /**
     * @See {@link android.media.ImageWriter}
     */
    public static ImageWriterProxy newInstance(Surface surface, int maxImages) {
        return new AndroidImageWriterProxy(android.media.ImageWriter.newInstance(surface, maxImages));
    }

	@Override
	public int getMaxImages() {
		synchronized (mLock) {
            return mDelegate.getMaxImages();
        }
	}

	@Override
	public int getFormat() {
		synchronized (mLock) {
            return mDelegate.getFormat();
        }
	}
	
	private static String imageFormatToString(int imageFormat) {
        switch (imageFormat) {
            case ImageFormat.JPEG:
                return "JPEG";
            case ImageFormat.NV16:
                return "NV16";
            case ImageFormat.NV21:
                return "NV21";
            case ImageFormat.RAW10:
                return "RAW10";
            case ImageFormat.RAW_SENSOR:
                return "RAW_SENSOR";
            case ImageFormat.RGB_565:
                return "RGB_565";
            case ImageFormat.UNKNOWN:
                return "UNKNOWN";
            case ImageFormat.YUV_420_888:
                return "YUV_420_888";
            case ImageFormat.YUY2:
                return "YUY2";
            case ImageFormat.YV12:
                return "YV12";
        }
        return Integer.toString(imageFormat);
    }

	@Override
	public ImageProxy dequeueInputImage() {
		synchronized (mLock) {
			Image image = mDelegate.dequeueInputImage();
            if (image == null) {
                return null;
            } else {
                return new AndroidImageProxy(image);
            }
        }
	}

	@Override
	public void queueInputImage(ImageProxy image) {
		synchronized (mLock) {
			mDelegate.queueInputImage(image.getSelf());
		}
	}
	
	public void setOnImageReleasedListener(
			final @Nonnull OnImageReleasedListener listener, 
    		@Nullable Handler handler) {
		synchronized (mLock) {
            mDelegate.setOnImageReleasedListener(
            		new android.media.ImageWriter.OnImageReleasedListener() {
				@Override
				public void onImageReleased(ImageWriter writer) {
					listener.onImageReleased(AndroidImageWriterProxy.this);
				}
			}, handler);
        }
	}

	@Override
	public void close() {
		synchronized (mLock) {
			boolean alreadyClosed = mClosed.getAndSet(true);
            if (alreadyClosed) {
                return;
            }
            mDelegate.close();
        }
	}
	
	@Override
	public boolean isClosed() {
		return mClosed.get();
	}
	
	@Override
    public String toString() {
        Objects.ToStringHelper tsh;
        synchronized (mLock) {
            tsh = Objects.toStringHelper(mDelegate);
        }
        return tsh.add("maxImages", getMaxImages())
                .add("format", imageFormatToString(getFormat()))
                .toString();
    }
}
